#include "drv_adc.h"

#include "lcd.h"
#include "drv_vbus_sw.h"
#include "menu_handle.h"

__IO uint16_t adc1_ordinary_valuetab[USBADC_AVERAGE_NUM][USBADC_CHANNEL_NUM];
__IO float adc1_val[USBADC_CHANNEL_NUM];
__IO uint8_t adc1_val_mutex; // 互斥锁

float usbadc_offset[4];

__IO uint8_t energy_round;

#define ADC_TEMP_BASE                    (1.26)
#define ADC_TEMP_SLOPE                   (-0.00423)

#define CURRENT_SENSOR_GAIN (50)
#define CURRENT_SAMPLING_RESISTOR_VALUE (0.03)

void usb_adc_gpio_init(void)
{
    gpio_init_type gpio_initstructure = {0};
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

    gpio_default_para_init(&gpio_initstructure);
    gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;
    gpio_initstructure.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_4 | GPIO_PINS_5;
    gpio_init(GPIOA, &gpio_initstructure);
    
    gpio_initstructure.gpio_pins = GPIO_PINS_0 | GPIO_PINS_2;
    gpio_init(GPIOB, &gpio_initstructure);
}

void usb_adc_dma_config(void)
{
    dma_init_type dma_init_struct;
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    nvic_irq_enable(DMA1_Channel1_IRQn, 5, 0);
    dma_reset(DMA1_CHANNEL1);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = USBADC_AVERAGE_NUM * USBADC_CHANNEL_NUM;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_init_struct.loop_mode_enable = TRUE;
    dma_init(DMA1_CHANNEL1, &dma_init_struct);
//    dma_flexible_config(DMA1, FLEX_CHANNEL2, DMA_FLEXIBLE_ADC1);

    dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
    dma_channel_enable(DMA1_CHANNEL1, TRUE);
}

void usb_adc_tmr_config(void)
{
    crm_periph_clock_enable(CRM_TMR3_PERIPH_CLOCK, TRUE);
    /* configure counter settings */
    // 1.6Khz
    tmr_base_init(TMR3, 9374, 7);
    tmr_cnt_dir_set(TMR3, TMR_COUNT_UP);
    tmr_clock_source_div_set(TMR3, TMR_CLOCK_DIV1);
    tmr_repetition_counter_set(TMR3, 0);
    tmr_period_buffer_enable(TMR3, FALSE);

    /* configure primary mode settings */
    tmr_primary_mode_select(TMR3, TMR_PRIMARY_SEL_OVERFLOW);
}

void usb_adc_config(void)
{
    adc_base_config_type adc_base_struct;
    crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
    crm_adc_clock_div_set(CRM_ADC_DIV_6);

    adc_base_default_para_init(&adc_base_struct);
    adc_base_struct.sequence_mode = TRUE;
    adc_base_struct.repeat_mode = FALSE;
    adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
    adc_base_struct.ordinary_channel_length = USBADC_CHANNEL_NUM;
    adc_base_config(ADC1, &adc_base_struct);
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_17, 1, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_0, 2, ADC_SAMPLETIME_239_5); // 12V_ADCIN
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_1, 3, ADC_SAMPLETIME_239_5); // 5V_ADCIN
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_4, 4, ADC_SAMPLETIME_239_5); // VBUS2_IOUT
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_5, 5, ADC_SAMPLETIME_239_5); // VBUS3_IOUT
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_8, 6, ADC_SAMPLETIME_239_5); // VBUS4_IOUT
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_10, 7, ADC_SAMPLETIME_239_5); // VBUS5_IOUT
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_16, 8, ADC_SAMPLETIME_239_5);
    adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_TMR3TRGOUT, TRUE);
    adc_dma_mode_enable(ADC1, TRUE);
    adc_tempersensor_vintrv_enable(TRUE);

    adc_enable(ADC1, TRUE);
    adc_calibration_init(ADC1);
    while(adc_calibration_init_status_get(ADC1));
    adc_calibration_start(ADC1);
    while(adc_calibration_status_get(ADC1));
    
    tmr_counter_enable(TMR3, TRUE);
}

static inline void usb_ovp_scan(void)
{
    float vref_value = (float)1.2 * 4095 / adc1_val[0];
    float vbus_value = (float)adc1_val[2] / 4095 * vref_value * 25 / 10;
    if(vbus_value > OVP_VOLTAGE)
    {
        VBUS1_OFF();
        VBUS2_OFF();
        VBUS3_OFF();
        VBUS4_OFF();
        
        hub_state.ovp_flag = 1;
    }
}

void DMA1_Channel1_IRQHandler(void)
{
    uint32_t average_num = 0;
    
    if(dma_flag_get(DMA1_FDT1_FLAG) != RESET)
    {
        // 计算平均值写入到adc1_val
        for(uint8_t i = 0;i < USBADC_CHANNEL_NUM;i++)
        {
            average_num = 0;
            for(uint8_t j = 0;j < USBADC_AVERAGE_NUM;j++)
            {
                average_num += adc1_ordinary_valuetab[j][i];
            }
            adc1_val[i] = average_num / 32.0f;
        }

        usb_ovp_scan();
        
        adc1_val_mutex = 1;
        dma_flag_clear(DMA1_FDT1_FLAG);
    }
}

void usb_adc_load_calibrate_data(void)
{
    const uint32_t SECTOR_SIZE = 1024;
    
    for(uint8_t i = 0;i < 4;i++)
    {
        // 127块为256K最后一个块,一个float占用32位4个字节
        uint32_t read_addr = 63 * SECTOR_SIZE + FLASH_BASE + (i * 4);
        usbadc_offset[i] = *(float*)(read_addr);
    }
}

void usb_adc_calibrate_offsets(void)
{
    // 校准0点
    static uint32_t usbadc_offset_tmp[4];
    adc_base_config_type adc_base_struct;
    crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
    crm_adc_clock_div_set(CRM_ADC_DIV_6);

    adc_base_default_para_init(&adc_base_struct);
    adc_base_struct.sequence_mode = TRUE;
    adc_base_struct.repeat_mode = FALSE;
    adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
    adc_base_struct.ordinary_channel_length = 0;
    adc_base_config(ADC1, &adc_base_struct);
    
    adc_preempt_channel_length_set(ADC1, 4);
    adc_preempt_channel_set(ADC1, ADC_CHANNEL_4, 1, ADC_SAMPLETIME_239_5);
    adc_preempt_channel_set(ADC1, ADC_CHANNEL_5, 2, ADC_SAMPLETIME_239_5);
    adc_preempt_channel_set(ADC1, ADC_CHANNEL_8, 3, ADC_SAMPLETIME_239_5);
    adc_preempt_channel_set(ADC1, ADC_CHANNEL_10, 4, ADC_SAMPLETIME_239_5);
    adc_preempt_conversion_trigger_set(ADC1, ADC12_PREEMPT_TRIG_SOFTWARE, TRUE);

    adc_enable(ADC1, TRUE);
    adc_calibration_init(ADC1);
    while(adc_calibration_init_status_get(ADC1));
    adc_calibration_start(ADC1);
    while(adc_calibration_status_get(ADC1));
    
    
    for(uint8_t i = 0;i < 4;i++)
    {
        usbadc_offset[i] = 0;
    }

    adc_flag_clear(ADC1, ADC_PCCE_FLAG);
    for(int i = 0; i < USBADC_CALIBRATION_ROUNDS; i++)
    {
        adc_preempt_software_trigger_enable(ADC1, TRUE);
        while(adc_flag_get(ADC1, ADC_PCCE_FLAG) == RESET);
        adc_flag_clear(ADC1, ADC_PCCE_FLAG);
        usbadc_offset[0] += (float)adc_preempt_conversion_data_get(ADC1, ADC_PREEMPT_CHANNEL_1);
        usbadc_offset[1] += (float)adc_preempt_conversion_data_get(ADC1, ADC_PREEMPT_CHANNEL_2);
        usbadc_offset[2] += (float)adc_preempt_conversion_data_get(ADC1, ADC_PREEMPT_CHANNEL_3);
        usbadc_offset[3] += (float)adc_preempt_conversion_data_get(ADC1, ADC_PREEMPT_CHANNEL_4);
    }
    
    for(uint8_t i = 0;i < 4;i++)
    {
        usbadc_offset[i] = usbadc_offset[i] / USBADC_CALIBRATION_ROUNDS;
    }

    // 校准完成复位
    adc_reset(ADC1);
    
    const uint32_t SECTOR_SIZE = 1024;
    // 开始保存校准结果
    flash_unlock();
    flash_status_type status = FLASH_OPERATE_DONE;
    /* wait for operation to be completed */
    status = flash_operation_wait_for(ERASE_TIMEOUT);

    if((status == FLASH_PROGRAM_ERROR) || (status == FLASH_EPP_ERROR))
    {
        flash_flag_clear(FLASH_PRGMERR_FLAG | FLASH_EPPERR_FLAG);
    }
    else if(status == FLASH_OPERATE_TIMEOUT)
    {
        LCD_ShowString(0, 0, (uint8_t*)"FLASH_OPERATE_TIMEOUT...", BLACK, RED, 20,0);
        goto end;
    }
    status = flash_sector_erase(63 * SECTOR_SIZE + FLASH_BASE);
    if(status != FLASH_OPERATE_DONE)
    {
        LCD_ShowString(0, 0, (uint8_t*)"FLASH_ERASE_FAILED", BLACK, RED, 20,0);
        goto end;
    }
    for(uint8_t i = 0;i < 4;i++)
    {
        // 63块为64K最后一个块,一个float占用32位4个字节
        status = flash_word_program(63 * SECTOR_SIZE + FLASH_BASE + (i * 4), *(uint32_t *)(&usbadc_offset[i]));
        if(status != FLASH_OPERATE_DONE)
        {
            LCD_ShowString(0, 0, (uint8_t*)"FLASH_PROGRAM_FAILED", BLACK, RED, 20,0);
            goto end;
        }
    }

end:
    flash_lock();
    delay_ms(200);
}

void usb_adc_calc_state(void)
{
    if(!adc1_val_mutex)
    {
        return;
    }
    adc1_val_mutex = 0;
    // ??????????
    adc1_val[3] -= usbadc_offset[0];
    adc1_val[4] -= usbadc_offset[1];
    adc1_val[5] -= usbadc_offset[2];
    adc1_val[6] -= usbadc_offset[3];
    // ??0????0
    for(uint8_t i = 3;i < 7;i++)
    {
        if(adc1_val[i] < 0)
        {
            adc1_val[i] = 0.0;
        }
    }
    
    hub_state.vref_value = (float)1.2 * 4095 / adc1_val[0];
    hub_state.vin_value =  (float)adc1_val[1] / 4095 * hub_state.vref_value * 11;
    hub_state.vbus_value = (float)adc1_val[2] / 4095 * hub_state.vref_value * 25 / 10;
    
    hub_state.port_state[0].current = (float)adc1_val[3] / 4095 * hub_state.vref_value / CURRENT_SENSOR_GAIN / CURRENT_SAMPLING_RESISTOR_VALUE * 1000;
    hub_state.port_state[1].current = (float)adc1_val[4] / 4095 * hub_state.vref_value / CURRENT_SENSOR_GAIN / CURRENT_SAMPLING_RESISTOR_VALUE * 1000;
    hub_state.port_state[2].current = (float)adc1_val[5] / 4095 * hub_state.vref_value / CURRENT_SENSOR_GAIN / CURRENT_SAMPLING_RESISTOR_VALUE * 1000;
    hub_state.port_state[3].current = (float)adc1_val[6] / 4095 * hub_state.vref_value / CURRENT_SENSOR_GAIN / CURRENT_SAMPLING_RESISTOR_VALUE * 1000;
    
    hub_state.all_current = 0.f;
    hub_state.all_power = 0.f;
    for(uint8_t i = 0; i < USB_PORT_NUM; i++)
    {
        hub_state.all_current += hub_state.port_state[i].current;
        
        hub_state.port_state[i].power = (hub_state.vbus_value * hub_state.port_state[i].current) / 1000;
        hub_state.all_power += hub_state.port_state[i].power;
    }
    
    if((++energy_round) == 5)
    {
        energy_round = 0;
        // energy statistics
        hub_state.all_energy += hub_state.all_power * (1 / 36000.0f); // Watt / h
    }
    
    hub_state.chip_temp = (ADC_TEMP_BASE - (float)adc1_val[7] * hub_state.vref_value / 4095) / ADC_TEMP_SLOPE + 25;
}
